package cn.seaboot.admin.security.jwt;

import cn.seaboot.commons.core.Converter;
import cn.seaboot.commons.core.UUIDUtils;
import cn.seaboot.commons.digest.RSA;
import cn.seaboot.commons.exception.SystemError;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.Authentication;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;

/**
 * 基于RS256算法实现，这个类暂不可用，公钥和私钥必须持久化
 *
 * @author Mr.css
 * @version 2022-01-05 15:03
 */
public class JwtRS256 implements AuthenticationJwt {

    /**
     * 公钥/私钥一般交由数据库管理
     */
    private PublicKey publicKey;
    private PrivateKey privateKey;

    @Resource
    private SecurityJwtProperties securityJwtProperties;

    /**
     * 初始化密钥
     */
    @PostConstruct
    public void init() {
        try {
            KeyPair keyPair = RSA.getKeyPair();
            publicKey = keyPair.getPublic();
            privateKey = keyPair.getPrivate();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        throw new SystemError("不能直接使用未经过设计的JwtRS256算法");
    }

    /**
     * 生成jwt
     *
     * @param authentication 登录凭证
     * @return jwt
     */
    @Override
    public String encrypt(Authentication authentication) {
        long millis = System.currentTimeMillis();
        Date now = new Date(millis);
        JwtBuilder builder = Jwts.builder();
        // 每一次都是唯一不可复制的
        builder.setId(UUIDUtils.genUUID22());
        // 主题，用户账号
        builder.setSubject(Converter.toString(authentication.getPrincipal()));
        //  签发时间
        builder.setIssuedAt(now);
        //  签名算法以及密匙
        builder.signWith(SignatureAlgorithm.HS256, privateKey);
        //  设置超时时间
        builder.setExpiration(new Date(millis + securityJwtProperties.getTimeoutMs()));
        return builder.compact();
    }

    /**
     * 解析JWT字符串
     *
     * @param jwt jwt
     * @return Claims
     */
    @Override
    public Claims decrypt(String jwt) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt).getBody();
    }
}
